Daniel Borkmann says:
[linux-block.git] / net / core / filter.c
index 727c5269867df98b082e9d831fe7d382d601e0f1..df0df59814ae208748caa0414f7f86a53bbfa17a 100644 (file)
@@ -2204,7 +2204,7 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb,
                        return -ENOMEM;
        }
 
-       rcu_read_lock_bh();
+       rcu_read_lock();
        if (!nh) {
                dst = skb_dst(skb);
                nexthop = rt6_nexthop(container_of(dst, struct rt6_info, dst),
@@ -2217,10 +2217,12 @@ static int bpf_out_neigh_v6(struct net *net, struct sk_buff *skb,
                int ret;
 
                sock_confirm_neigh(skb, neigh);
+               local_bh_disable();
                dev_xmit_recursion_inc();
                ret = neigh_output(neigh, skb, false);
                dev_xmit_recursion_dec();
-               rcu_read_unlock_bh();
+               local_bh_enable();
+               rcu_read_unlock();
                return ret;
        }
        rcu_read_unlock_bh();
@@ -2302,7 +2304,7 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb,
                        return -ENOMEM;
        }
 
-       rcu_read_lock_bh();
+       rcu_read_lock();
        if (!nh) {
                struct dst_entry *dst = skb_dst(skb);
                struct rtable *rt = container_of(dst, struct rtable, dst);
@@ -2314,7 +2316,7 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb,
        } else if (nh->nh_family == AF_INET) {
                neigh = ip_neigh_gw4(dev, nh->ipv4_nh);
        } else {
-               rcu_read_unlock_bh();
+               rcu_read_unlock();
                goto out_drop;
        }
 
@@ -2322,13 +2324,15 @@ static int bpf_out_neigh_v4(struct net *net, struct sk_buff *skb,
                int ret;
 
                sock_confirm_neigh(skb, neigh);
+               local_bh_disable();
                dev_xmit_recursion_inc();
                ret = neigh_output(neigh, skb, is_v6gw);
                dev_xmit_recursion_dec();
-               rcu_read_unlock_bh();
+               local_bh_enable();
+               rcu_read_unlock();
                return ret;
        }
-       rcu_read_unlock_bh();
+       rcu_read_unlock();
 out_drop:
        kfree_skb(skb);
        return -ENETDOWN;
@@ -5871,7 +5875,7 @@ static int bpf_ipv4_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
        else
                neigh = __ipv6_neigh_lookup_noref_stub(dev, params->ipv6_dst);
 
-       if (!neigh || !(neigh->nud_state & NUD_VALID))
+       if (!neigh || !(READ_ONCE(neigh->nud_state) & NUD_VALID))
                return BPF_FIB_LKUP_RET_NO_NEIGH;
        memcpy(params->dmac, neigh->ha, ETH_ALEN);
        memcpy(params->smac, dev->dev_addr, ETH_ALEN);
@@ -5992,7 +5996,7 @@ static int bpf_ipv6_fib_lookup(struct net *net, struct bpf_fib_lookup *params,
         * not needed here.
         */
        neigh = __ipv6_neigh_lookup_noref_stub(dev, dst);
-       if (!neigh || !(neigh->nud_state & NUD_VALID))
+       if (!neigh || !(READ_ONCE(neigh->nud_state) & NUD_VALID))
                return BPF_FIB_LKUP_RET_NO_NEIGH;
        memcpy(params->dmac, neigh->ha, ETH_ALEN);
        memcpy(params->smac, dev->dev_addr, ETH_ALEN);