]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
net: lwtunnel: disable BHs when required
authorJustin Iurman <justin.iurman@uliege.be>
Wed, 16 Apr 2025 16:07:16 +0000 (18:07 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 2 May 2025 05:50:43 +0000 (07:50 +0200)
[ Upstream commit c03a49f3093a4903c8a93c8b5c9a297b5343b169 ]

In lwtunnel_{output|xmit}(), dev_xmit_recursion() may be called in
preemptible scope for PREEMPT kernels. This patch disables BHs before
calling dev_xmit_recursion(). BHs are re-enabled only at the end, since
we must ensure the same CPU is used for both dev_xmit_recursion_inc()
and dev_xmit_recursion_dec() (and any other recursion levels in some
cases) in order to maintain valid per-cpu counters.

Reported-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
Closes: https://lore.kernel.org/netdev/CAADnVQJFWn3dBFJtY+ci6oN1pDFL=TzCmNbRgey7MdYxt_AP2g@mail.gmail.com/
Reported-by: Eduard Zingerman <eddyz87@gmail.com>
Closes: https://lore.kernel.org/netdev/m2h62qwf34.fsf@gmail.com/
Fixes: 986ffb3a57c5 ("net: lwtunnel: fix recursion loops")
Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
Reviewed-by: Simon Horman <horms@kernel.org>
Link: https://patch.msgid.link/20250416160716.8823-1-justin.iurman@uliege.be
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
net/core/lwtunnel.c

index 4417a18b3e951aa4bd62b6964a47c49e6fa8e919..f63586c9ce02168c8651015d08eb012c9a3a23ff 100644 (file)
@@ -332,6 +332,8 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
        struct dst_entry *dst;
        int ret;
 
+       local_bh_disable();
+
        if (dev_xmit_recursion()) {
                net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
                                     __func__);
@@ -347,8 +349,10 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
        lwtstate = dst->lwtstate;
 
        if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
-           lwtstate->type > LWTUNNEL_ENCAP_MAX)
-               return 0;
+           lwtstate->type > LWTUNNEL_ENCAP_MAX) {
+               ret = 0;
+               goto out;
+       }
 
        ret = -EOPNOTSUPP;
        rcu_read_lock();
@@ -363,11 +367,13 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
        if (ret == -EOPNOTSUPP)
                goto drop;
 
-       return ret;
+       goto out;
 
 drop:
        kfree_skb(skb);
 
+out:
+       local_bh_enable();
        return ret;
 }
 EXPORT_SYMBOL_GPL(lwtunnel_output);
@@ -379,6 +385,8 @@ int lwtunnel_xmit(struct sk_buff *skb)
        struct dst_entry *dst;
        int ret;
 
+       local_bh_disable();
+
        if (dev_xmit_recursion()) {
                net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
                                     __func__);
@@ -395,8 +403,10 @@ int lwtunnel_xmit(struct sk_buff *skb)
        lwtstate = dst->lwtstate;
 
        if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
-           lwtstate->type > LWTUNNEL_ENCAP_MAX)
-               return 0;
+           lwtstate->type > LWTUNNEL_ENCAP_MAX) {
+               ret = 0;
+               goto out;
+       }
 
        ret = -EOPNOTSUPP;
        rcu_read_lock();
@@ -411,11 +421,13 @@ int lwtunnel_xmit(struct sk_buff *skb)
        if (ret == -EOPNOTSUPP)
                goto drop;
 
-       return ret;
+       goto out;
 
 drop:
        kfree_skb(skb);
 
+out:
+       local_bh_enable();
        return ret;
 }
 EXPORT_SYMBOL_GPL(lwtunnel_xmit);
@@ -427,6 +439,8 @@ int lwtunnel_input(struct sk_buff *skb)
        struct dst_entry *dst;
        int ret;
 
+       DEBUG_NET_WARN_ON_ONCE(!in_softirq());
+
        if (dev_xmit_recursion()) {
                net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
                                     __func__);