Commit 580da35a31f91a594f3090b7a2c39b85cb051a12
Committed by
Roland Dreier
1 parent
1ea6b8f489
Exists in
master
and in
6 other branches
IB: Fix RCU lockdep splats
Commit f2c31e32b37 ("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 <tsi@ualberta.ca> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Cc: David Miller <davem@davemloft.net> Cc: <stable@kernel.org> Signed-off-by: Roland Dreier <roland@purestorage.com>
Showing 6 changed files with 35 additions and 14 deletions Side-by-side Diff
drivers/infiniband/core/addr.c
... | ... | @@ -216,7 +216,9 @@ |
216 | 216 | |
217 | 217 | neigh = neigh_lookup(&arp_tbl, &rt->rt_gateway, rt->dst.dev); |
218 | 218 | if (!neigh || !(neigh->nud_state & NUD_VALID)) { |
219 | + rcu_read_lock(); | |
219 | 220 | neigh_event_send(dst_get_neighbour(&rt->dst), NULL); |
221 | + rcu_read_unlock(); | |
220 | 222 | ret = -ENODATA; |
221 | 223 | if (neigh) |
222 | 224 | goto release; |
223 | 225 | |
224 | 226 | |
... | ... | @@ -274,15 +276,16 @@ |
274 | 276 | goto put; |
275 | 277 | } |
276 | 278 | |
279 | + rcu_read_lock(); | |
277 | 280 | neigh = dst_get_neighbour(dst); |
278 | 281 | if (!neigh || !(neigh->nud_state & NUD_VALID)) { |
279 | 282 | if (neigh) |
280 | 283 | neigh_event_send(neigh, NULL); |
281 | 284 | ret = -ENODATA; |
282 | - goto put; | |
285 | + } else { | |
286 | + ret = rdma_copy_addr(addr, dst->dev, neigh->ha); | |
283 | 287 | } |
284 | - | |
285 | - ret = rdma_copy_addr(addr, dst->dev, neigh->ha); | |
288 | + rcu_read_unlock(); | |
286 | 289 | put: |
287 | 290 | dst_release(dst); |
288 | 291 | return ret; |
drivers/infiniband/hw/cxgb3/iwch_cm.c
... | ... | @@ -1375,8 +1375,10 @@ |
1375 | 1375 | goto reject; |
1376 | 1376 | } |
1377 | 1377 | dst = &rt->dst; |
1378 | + rcu_read_lock(); | |
1378 | 1379 | neigh = dst_get_neighbour(dst); |
1379 | 1380 | l2t = t3_l2t_get(tdev, neigh, neigh->dev); |
1381 | + rcu_read_unlock(); | |
1380 | 1382 | if (!l2t) { |
1381 | 1383 | printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n", |
1382 | 1384 | __func__); |
1383 | 1385 | |
... | ... | @@ -1946,10 +1948,12 @@ |
1946 | 1948 | } |
1947 | 1949 | ep->dst = &rt->dst; |
1948 | 1950 | |
1951 | + rcu_read_lock(); | |
1949 | 1952 | neigh = dst_get_neighbour(ep->dst); |
1950 | 1953 | |
1951 | 1954 | /* get a l2t entry */ |
1952 | 1955 | ep->l2t = t3_l2t_get(ep->com.tdev, neigh, neigh->dev); |
1956 | + rcu_read_unlock(); | |
1953 | 1957 | if (!ep->l2t) { |
1954 | 1958 | printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); |
1955 | 1959 | err = -ENOMEM; |
drivers/infiniband/hw/cxgb4/cm.c
... | ... | @@ -1594,6 +1594,7 @@ |
1594 | 1594 | goto reject; |
1595 | 1595 | } |
1596 | 1596 | dst = &rt->dst; |
1597 | + rcu_read_lock(); | |
1597 | 1598 | neigh = dst_get_neighbour(dst); |
1598 | 1599 | if (neigh->dev->flags & IFF_LOOPBACK) { |
1599 | 1600 | pdev = ip_dev_find(&init_net, peer_ip); |
... | ... | @@ -1620,6 +1621,7 @@ |
1620 | 1621 | rss_qid = dev->rdev.lldi.rxq_ids[ |
1621 | 1622 | cxgb4_port_idx(neigh->dev) * step]; |
1622 | 1623 | } |
1624 | + rcu_read_unlock(); | |
1623 | 1625 | if (!l2t) { |
1624 | 1626 | printk(KERN_ERR MOD "%s - failed to allocate l2t entry!\n", |
1625 | 1627 | __func__); |
... | ... | @@ -1820,6 +1822,7 @@ |
1820 | 1822 | } |
1821 | 1823 | ep->dst = &rt->dst; |
1822 | 1824 | |
1825 | + rcu_read_lock(); | |
1823 | 1826 | neigh = dst_get_neighbour(ep->dst); |
1824 | 1827 | |
1825 | 1828 | /* get a l2t entry */ |
... | ... | @@ -1856,6 +1859,7 @@ |
1856 | 1859 | ep->rss_qid = ep->com.dev->rdev.lldi.rxq_ids[ |
1857 | 1860 | cxgb4_port_idx(neigh->dev) * step]; |
1858 | 1861 | } |
1862 | + rcu_read_unlock(); | |
1859 | 1863 | if (!ep->l2t) { |
1860 | 1864 | printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); |
1861 | 1865 | err = -ENOMEM; |
... | ... | @@ -2301,6 +2305,7 @@ |
2301 | 2305 | } |
2302 | 2306 | ep->dst = &rt->dst; |
2303 | 2307 | |
2308 | + rcu_read_lock(); | |
2304 | 2309 | neigh = dst_get_neighbour(ep->dst); |
2305 | 2310 | |
2306 | 2311 | /* get a l2t entry */ |
... | ... | @@ -2339,6 +2344,7 @@ |
2339 | 2344 | ep->retry_with_mpa_v1 = 0; |
2340 | 2345 | ep->tried_with_mpa_v1 = 0; |
2341 | 2346 | } |
2347 | + rcu_read_unlock(); | |
2342 | 2348 | if (!ep->l2t) { |
2343 | 2349 | printk(KERN_ERR MOD "%s - cannot alloc l2e.\n", __func__); |
2344 | 2350 | err = -ENOMEM; |
drivers/infiniband/hw/nes/nes_cm.c
... | ... | @@ -1377,9 +1377,11 @@ |
1377 | 1377 | neigh_release(neigh); |
1378 | 1378 | } |
1379 | 1379 | |
1380 | - if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) | |
1380 | + if ((neigh == NULL) || (!(neigh->nud_state & NUD_VALID))) { | |
1381 | + rcu_read_lock(); | |
1381 | 1382 | neigh_event_send(dst_get_neighbour(&rt->dst), NULL); |
1382 | - | |
1383 | + rcu_read_unlock(); | |
1384 | + } | |
1383 | 1385 | ip_rt_put(rt); |
1384 | 1386 | return rc; |
1385 | 1387 | } |
drivers/infiniband/ulp/ipoib/ipoib_main.c
... | ... | @@ -555,6 +555,7 @@ |
555 | 555 | return 0; |
556 | 556 | } |
557 | 557 | |
558 | +/* called with rcu_read_lock */ | |
558 | 559 | static void neigh_add_path(struct sk_buff *skb, struct net_device *dev) |
559 | 560 | { |
560 | 561 | struct ipoib_dev_priv *priv = netdev_priv(dev); |
... | ... | @@ -636,6 +637,7 @@ |
636 | 637 | spin_unlock_irqrestore(&priv->lock, flags); |
637 | 638 | } |
638 | 639 | |
640 | +/* called with rcu_read_lock */ | |
639 | 641 | static void ipoib_path_lookup(struct sk_buff *skb, struct net_device *dev) |
640 | 642 | { |
641 | 643 | struct ipoib_dev_priv *priv = netdev_priv(skb->dev); |
642 | 644 | |
... | ... | @@ -720,13 +722,14 @@ |
720 | 722 | struct neighbour *n = NULL; |
721 | 723 | unsigned long flags; |
722 | 724 | |
725 | + rcu_read_lock(); | |
723 | 726 | if (likely(skb_dst(skb))) |
724 | 727 | n = dst_get_neighbour(skb_dst(skb)); |
725 | 728 | |
726 | 729 | if (likely(n)) { |
727 | 730 | if (unlikely(!*to_ipoib_neigh(n))) { |
728 | 731 | ipoib_path_lookup(skb, dev); |
729 | - return NETDEV_TX_OK; | |
732 | + goto unlock; | |
730 | 733 | } |
731 | 734 | |
732 | 735 | neigh = *to_ipoib_neigh(n); |
733 | 736 | |
734 | 737 | |
... | ... | @@ -749,17 +752,17 @@ |
749 | 752 | ipoib_neigh_free(dev, neigh); |
750 | 753 | spin_unlock_irqrestore(&priv->lock, flags); |
751 | 754 | ipoib_path_lookup(skb, dev); |
752 | - return NETDEV_TX_OK; | |
755 | + goto unlock; | |
753 | 756 | } |
754 | 757 | |
755 | 758 | if (ipoib_cm_get(neigh)) { |
756 | 759 | if (ipoib_cm_up(neigh)) { |
757 | 760 | ipoib_cm_send(dev, skb, ipoib_cm_get(neigh)); |
758 | - return NETDEV_TX_OK; | |
761 | + goto unlock; | |
759 | 762 | } |
760 | 763 | } else if (neigh->ah) { |
761 | 764 | ipoib_send(dev, skb, neigh->ah, IPOIB_QPN(n->ha)); |
762 | - return NETDEV_TX_OK; | |
765 | + goto unlock; | |
763 | 766 | } |
764 | 767 | |
765 | 768 | if (skb_queue_len(&neigh->queue) < IPOIB_MAX_PATH_REC_QUEUE) { |
766 | 769 | |
... | ... | @@ -793,13 +796,14 @@ |
793 | 796 | phdr->hwaddr + 4); |
794 | 797 | dev_kfree_skb_any(skb); |
795 | 798 | ++dev->stats.tx_dropped; |
796 | - return NETDEV_TX_OK; | |
799 | + goto unlock; | |
797 | 800 | } |
798 | 801 | |
799 | 802 | unicast_arp_send(skb, dev, phdr); |
800 | 803 | } |
801 | 804 | } |
802 | - | |
805 | +unlock: | |
806 | + rcu_read_unlock(); | |
803 | 807 | return NETDEV_TX_OK; |
804 | 808 | } |
805 | 809 | |
... | ... | @@ -837,7 +841,7 @@ |
837 | 841 | dst = skb_dst(skb); |
838 | 842 | n = NULL; |
839 | 843 | if (dst) |
840 | - n = dst_get_neighbour(dst); | |
844 | + n = dst_get_neighbour_raw(dst); | |
841 | 845 | if ((!dst || !n) && daddr) { |
842 | 846 | struct ipoib_pseudoheader *phdr = |
843 | 847 | (struct ipoib_pseudoheader *) skb_push(skb, sizeof *phdr); |
drivers/infiniband/ulp/ipoib/ipoib_multicast.c
... | ... | @@ -266,7 +266,7 @@ |
266 | 266 | |
267 | 267 | skb->dev = dev; |
268 | 268 | if (dst) |
269 | - n = dst_get_neighbour(dst); | |
269 | + n = dst_get_neighbour_raw(dst); | |
270 | 270 | if (!dst || !n) { |
271 | 271 | /* put pseudoheader back on for next time */ |
272 | 272 | skb_push(skb, sizeof (struct ipoib_pseudoheader)); |
... | ... | @@ -722,6 +722,8 @@ |
722 | 722 | if (mcast && mcast->ah) { |
723 | 723 | struct dst_entry *dst = skb_dst(skb); |
724 | 724 | struct neighbour *n = NULL; |
725 | + | |
726 | + rcu_read_lock(); | |
725 | 727 | if (dst) |
726 | 728 | n = dst_get_neighbour(dst); |
727 | 729 | if (n && !*to_ipoib_neigh(n)) { |
... | ... | @@ -734,7 +736,7 @@ |
734 | 736 | list_add_tail(&neigh->list, &mcast->neigh_list); |
735 | 737 | } |
736 | 738 | } |
737 | - | |
739 | + rcu_read_unlock(); | |
738 | 740 | spin_unlock_irqrestore(&priv->lock, flags); |
739 | 741 | ipoib_send(dev, skb, mcast->ah, IB_MULTICAST_QPN); |
740 | 742 | return; |