Skip to content

Commit 580da35

Browse files
Eric Dumazetrolandd
authored andcommitted
IB: Fix RCU lockdep splats
Commit f2c31e3 ("net: fix NULL dereferences in check_peer_redir()") forgot to take care of infiniband uses of dst neighbours. Many thanks to Marc Aurele who provided a nice bug report and feedback. Reported-by: Marc Aurele La France <[email protected]> Signed-off-by: Eric Dumazet <[email protected]> Cc: David Miller <[email protected]> Cc: <[email protected]> Signed-off-by: Roland Dreier <[email protected]>
1 parent 1ea6b8f commit 580da35

File tree

6 files changed

+35
-14
lines changed

6 files changed

+35
-14
lines changed

drivers/infiniband/core/addr.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,9 @@ static int addr4_resolve(struct sockaddr_in *src_in,
216216

217217
neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev);
218218
if (!neigh || !(neigh->nud_state & NUD_VALID)) {
219+
rcu_read_lock();
219220
neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
221+
rcu_read_unlock();
220222
ret = -ENODATA;
221223
if (neigh)
222224
goto release;
@@ -274,15 +276,16 @@ static int addr6_resolve(struct sockaddr_in6 *src_in,
274276
goto put;
275277
}
276278

279+
rcu_read_lock();
277280
neigh = dst_get_neighbour(dst);
278281
if (!neigh || !(neigh->nud_state & NUD_VALID)) {
279282
if (neigh)
280283
neigh_event_send(neigh, NULL);
281284
ret = -ENODATA;
282-
goto put;
285+
} else {
286+
ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
283287
}
284-
285-
ret = rdma_copy_addr(addr, dst->dev, neigh->ha);
288+
rcu_read_unlock();
286289
put:
287290
dst_release(dst);
288291
return ret;

drivers/infiniband/hw/cxgb3/iwch_cm.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,8 +1375,10 @@ static int pass_accept_req(struct t3cdev *tdev, struct sk_buff *skb, void *ctx)
13751375
goto reject;
13761376
}
13771377
dst = &rt->dst;
1378+
rcu_read_lock();
13781379
neigh = dst_get_neighbour(dst);
13791380
l2t = t3_l2t_get(tdev, neigh, neigh->dev);
1381+
rcu_read_unlock();
13801382
if (!l2t) {
13811383
printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
13821384
__func__);
@@ -1946,10 +1948,12 @@ int iwch_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
19461948
}
19471949
ep->dst = &rt->dst;
19481950

1951+
rcu_read_lock();
19491952
neigh = dst_get_neighbour(ep->dst);
19501953

19511954
/* get a l2t entry */
19521955
ep->l2t = t3_l2t_get(ep->com.tdev, neigh, neigh->dev);
1956+
rcu_read_unlock();
19531957
if (!ep->l2t) {
19541958
printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
19551959
err = -ENOMEM;

drivers/infiniband/hw/cxgb4/cm.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1594,6 +1594,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
15941594
goto reject;
15951595
}
15961596
dst = &rt->dst;
1597+
rcu_read_lock();
15971598
neigh = dst_get_neighbour(dst);
15981599
if (neigh->dev->flags & IFF_LOOPBACK) {
15991600
pdev = ip_dev_find(&init_net, peer_ip);
@@ -1620,6 +1621,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
16201621
rss_qid = dev->rdev.lldi.rxq_ids[
16211622
cxgb4_port_idx(neigh->dev) * step];
16221623
}
1624+
rcu_read_unlock();
16231625
if (!l2t) {
16241626
printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n",
16251627
__func__);
@@ -1820,6 +1822,7 @@ static int c4iw_reconnect(struct c4iw_ep *ep)
18201822
}
18211823
ep->dst = &rt->dst;
18221824

1825+
rcu_read_lock();
18231826
neigh = dst_get_neighbour(ep->dst);
18241827

18251828
/* get a l2t entry */
@@ -1856,6 +1859,7 @@ static int c4iw_reconnect(struct c4iw_ep *ep)
18561859
ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[
18571860
cxgb4_port_idx(neigh->dev) * step];
18581861
}
1862+
rcu_read_unlock();
18591863
if (!ep->l2t) {
18601864
printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
18611865
err = -ENOMEM;
@@ -2301,6 +2305,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
23012305
}
23022306
ep->dst = &rt->dst;
23032307

2308+
rcu_read_lock();
23042309
neigh = dst_get_neighbour(ep->dst);
23052310

23062311
/* get a l2t entry */
@@ -2339,6 +2344,7 @@ int c4iw_connect(struct iw_cm_id *cm_id, struct iw_cm_conn_param *conn_param)
23392344
ep->retry_with_mpa_v1 = 0;
23402345
ep->tried_with_mpa_v1 = 0;
23412346
}
2347+
rcu_read_unlock();
23422348
if (!ep->l2t) {
23432349
printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__);
23442350
err = -ENOMEM;

drivers/infiniband/hw/nes/nes_cm.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1377,9 +1377,11 @@ static int nes_addr_resolve_neigh(struct nes_vnic *nesvnic, u32 dst_ip, int arpi
13771377
neigh_release(neigh);
13781378
}
13791379

1380-
if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID)))
1380+
if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) {
1381+
rcu_read_lock();
13811382
neigh_event_send(dst_get_neighbour(&rt->dst), NULL);
1382-
1383+
rcu_read_unlock();
1384+
}
13831385
ip_rt_put(rt);
13841386
return rc;
13851387
}

drivers/infiniband/ulp/ipoib/ipoib_main.c

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -555,6 +555,7 @@ static int path_rec_start(struct net_device *dev,
555555
return 0;
556556
}
557557

558+
/* called with rcu_read_lock */
558559
static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
559560
{
560561
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -636,6 +637,7 @@ static void neigh_add_path(struct sk_buff *skb, struct net_device *dev)
636637
spin_unlock_irqrestore(&priv->lock, flags);
637638
}
638639

640+
/* called with rcu_read_lock */
639641
static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev)
640642
{
641643
struct ipoib_dev_priv *priv = netdev_priv(skb->dev);
@@ -720,13 +722,14 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
720722
struct neighbour *n = NULL;
721723
unsigned long flags;
722724

725+
rcu_read_lock();
723726
if (likely(skb_dst(skb)))
724727
n = dst_get_neighbour(skb_dst(skb));
725728

726729
if (likely(n)) {
727730
if (unlikely(!*to_ipoib_neigh(n))) {
728731
ipoib_path_lookup(skb, dev);
729-
return NETDEV_TX_OK;
732+
goto unlock;
730733
}
731734

732735
neigh = *to_ipoib_neigh(n);
@@ -749,17 +752,17 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
749752
ipoib_neigh_free(dev, neigh);
750753
spin_unlock_irqrestore(&priv->lock, flags);
751754
ipoib_path_lookup(skb, dev);
752-
return NETDEV_TX_OK;
755+
goto unlock;
753756
}
754757

755758
if (ipoib_cm_get(neigh)) {
756759
if (ipoib_cm_up(neigh)) {
757760
ipoib_cm_send(dev, skb, ipoib_cm_get(neigh));
758-
return NETDEV_TX_OK;
761+
goto unlock;
759762
}
760763
} else if (neigh->ah) {
761764
ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(n->ha));
762-
return NETDEV_TX_OK;
765+
goto unlock;
763766
}
764767

765768
if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) {
@@ -793,13 +796,14 @@ static int ipoib_start_xmit(struct sk_buff *skb, struct net_device *dev)
793796
phdr->hwaddr + 4);
794797
dev_kfree_skb_any(skb);
795798
++dev->stats.tx_dropped;
796-
return NETDEV_TX_OK;
799+
goto unlock;
797800
}
798801

799802
unicast_arp_send(skb, dev, phdr);
800803
}
801804
}
802-
805+
unlock:
806+
rcu_read_unlock();
803807
return NETDEV_TX_OK;
804808
}
805809

@@ -837,7 +841,7 @@ static int ipoib_hard_header(struct sk_buff *skb,
837841
dst = skb_dst(skb);
838842
n = NULL;
839843
if (dst)
840-
n = dst_get_neighbour(dst);
844+
n = dst_get_neighbour_raw(dst);
841845
if ((!dst || !n) && daddr) {
842846
struct ipoib_pseudoheader *phdr =
843847
(struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr);

drivers/infiniband/ulp/ipoib/ipoib_multicast.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
266266

267267
skb->dev = dev;
268268
if (dst)
269-
n = dst_get_neighbour(dst);
269+
n = dst_get_neighbour_raw(dst);
270270
if (!dst || !n) {
271271
/* put pseudoheader back on for next time */
272272
skb_push(skb, sizeof (struct ipoib_pseudoheader));
@@ -722,6 +722,8 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
722722
if (mcast && mcast->ah) {
723723
struct dst_entry *dst = skb_dst(skb);
724724
struct neighbour *n = NULL;
725+
726+
rcu_read_lock();
725727
if (dst)
726728
n = dst_get_neighbour(dst);
727729
if (n && !*to_ipoib_neigh(n)) {
@@ -734,7 +736,7 @@ void ipoib_mcast_send(struct net_device *dev, void *mgid, struct sk_buff *skb)
734736
list_add_tail(&neigh->list, &mcast->neigh_list);
735737
}
736738
}
737-
739+
rcu_read_unlock();
738740
spin_unlock_irqrestore(&priv->lock, flags);
739741
ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN);
740742
return;

0 commit comments

Comments
 (0)