On Sun, 2010-03-28 at 09:02 -0700, Eli Cohen wrote: > On Thu, Mar 04, 2010 at 10:58:27AM -0800, Ralph Campbell wrote: > > Subject: [PATCH v3] IB/ipoib: fix dangling pointer references to > > ipoib_neigh and ipoib_path > > > > When using connected mode, ipoib_cm_create_tx() kmallocs a > > struct ipoib_cm_tx which contains pointers to ipoib_neigh and > > ipoib_path. If the paths are flushed or the struct neighbour is > > destroyed, the pointers held by struct ipoib_cm_tx can reference > > freed memory. > > > I could use some more content here as this is quite a large patch. > Anyway below are some comments. I think besides reviewing this patch > we need to make sure it has been checked in real life.
Do you mean more details about how ipoib_cm_tx can be used after being freed or more about how the changes fix the problem? I have been waiting for our internal regression tests to finish and to collect review feedback before sending out the final version of the patch. > > +/* > > + * Search the list of connections to be started and remove any entries > > + * which match the path being destroyed. > > + * > > + * This should be called with netif_tx_lock_bh() and priv->lock held. > > + */ > > +void ipoib_cm_flush_path(struct net_device *dev, struct ipoib_path *path) > > +{ > > + struct ipoib_dev_priv *priv = netdev_priv(dev); > > + struct ipoib_cm_tx *tx; > > + > > + list_for_each_entry(tx, &priv->cm.start_list, list) { > > + tx = list_entry(priv->cm.start_list.next, typeof(*tx), list); > > + if (tx->path == path) { > > + tx->path = NULL; > > + list_del_init(&tx->list); > > + break; > > + } > > } > > } > > Looks to me like we may find struct ipoib_cm_tx objects hanging and > not freed. This could happen if they were just added to start_list and > removed by ipoib_cm_flush_path() before being processed by > ipoib_cm_tx_start(). Quite right. I should also use list_for_each_entry_safe(). I will fix this. > > -static int __path_add(struct net_device *dev, struct ipoib_path *path) > > +static void __path_add(struct net_device *dev, struct ipoib_path *path) > > { > > struct ipoib_dev_priv *priv = netdev_priv(dev); > > struct rb_node **n = &priv->path_tree.rb_node; > > @@ -249,44 +252,26 @@ static int __path_add(struct net_device *dev, struct > > ipoib_path *path) > > n = &pn->rb_left; > > else if (ret > 0) > > n = &pn->rb_right; > > - else > > - return -EEXIST; > > + else /* Should never happen since we always search first */ > > + return; > > } > > Why not remove the last else and change the "else if" into else? I don't understand. This is left, right, or return. I'm only changing the return value to void since it is never used. > > } > > @@ -460,19 +446,13 @@ static void path_rec_completion(int status, > > memcpy(&neigh->dgid.raw, &path->pathrec.dgid.raw, > > sizeof(union ib_gid)); > > > > - if (ipoib_cm_enabled(dev, neigh->neighbour)) { > > - if (!ipoib_cm_get(neigh)) > > - ipoib_cm_set(neigh, > > ipoib_cm_create_tx(dev, > > - > > path, > > - > > neigh)); > > - if (!ipoib_cm_get(neigh)) { > > - list_del(&neigh->list); > > - if (neigh->ah) > > - ipoib_put_ah(neigh->ah); > > - ipoib_neigh_free(dev, neigh); > > - continue; > > - } > > - } > ipoib_cm_set() is called only once in neigh_alloc(), setting neigh->cm > to NULL, and never again so all calls to ipoib_cm_get() will return > NULL. ipoib_cm_set() is only called once since I changed ipoib_cm_create_tx() to initialize neigh->cm and return void. To me, it is more clear to let ipoib_cm.c do as much of the CM specific work as possible instead of defining two versions of a function for when CM is compiled in or not. I guess I could change neigh_alloc() to call kzmalloc() and remove ipoib_cm_set(). Normally, I would define set/get pairs but ipoib_main.c doesn't really need to use the pointer, just know that it has been allocated and be able to pass it to ipoib_cm.c I guess we could hide more of the details by just passing neigh and letting the CM functions get the ipoib_cm_tx pointer. It is all a matter of style so I'm OK with changing it back to the original or making it a separate patch (probably wiser). -- To unsubscribe from this list: send the line "unsubscribe linux-rdma" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html