Skip to content

Commit

Permalink
net: lwtunnel: fix recursion loops
Browse files Browse the repository at this point in the history
This patch acts as a parachute, catch all solution, by detecting
recursion loops in lwtunnel users and taking care of them (e.g., a loop
between routes, a loop within the same route, etc). In general, such
loops are the consequence of pathological configurations. Each lwtunnel
user is still free to catch such loops early and do whatever they want
with them. It will be the case in a separate patch for, e.g., seg6 and
seg6_local, in order to provide drop reasons and update statistics.
Another example of a lwtunnel user taking care of loops is ioam6, which
has valid use cases that include loops (e.g., inline mode), and which is
addressed by the next patch in this series. Overall, this patch acts as
a last resort to catch loops and drop packets, since we don't want to
leak something unintentionally because of a pathological configuration
in lwtunnels.

The solution in this patch reuses dev_xmit_recursion(),
dev_xmit_recursion_inc(), and dev_xmit_recursion_dec(), which seems fine
considering the context.

Closes: https://lore.kernel.org/netdev/2bc9e2079e864a9290561894d2a602d6@akamai.com/
Closes: https://lore.kernel.org/netdev/Z7NKYMY7fJT5cYWu@shredder/
Fixes: ffce419 ("lwtunnel: support dst output redirect function")
Fixes: 2536862 ("lwt: Add support to redirect dst.input")
Fixes: 14972cb ("net: lwtunnel: Handle fragmentation")
Signed-off-by: Justin Iurman <justin.iurman@uliege.be>
Link: https://patch.msgid.link/20250314120048.12569-2-justin.iurman@uliege.be
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Justin Iurman authored and Paolo Abeni committed Mar 20, 2025
1 parent 47a9b5e commit 986ffb3
Showing 1 changed file with 53 additions and 12 deletions.
65 changes: 53 additions & 12 deletions net/core/lwtunnel.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <net/ip6_fib.h>
#include <net/rtnh.h>

#include "dev.h"

DEFINE_STATIC_KEY_FALSE(nf_hooks_lwtunnel_enabled);
EXPORT_SYMBOL_GPL(nf_hooks_lwtunnel_enabled);

Expand Down Expand Up @@ -325,13 +327,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_cmp_encap);

int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
const struct lwtunnel_encap_ops *ops;
struct lwtunnel_state *lwtstate;
int ret = -EINVAL;
struct dst_entry *dst;
int ret;

if (dev_xmit_recursion()) {
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
__func__);
ret = -ENETDOWN;
goto drop;
}

if (!dst)
dst = skb_dst(skb);
if (!dst) {
ret = -EINVAL;
goto drop;
}
lwtstate = dst->lwtstate;

if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
Expand All @@ -341,8 +353,11 @@ int lwtunnel_output(struct net *net, struct sock *sk, struct sk_buff *skb)
ret = -EOPNOTSUPP;
rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
if (likely(ops && ops->output))
if (likely(ops && ops->output)) {
dev_xmit_recursion_inc();
ret = ops->output(net, sk, skb);
dev_xmit_recursion_dec();
}
rcu_read_unlock();

if (ret == -EOPNOTSUPP)
Expand All @@ -359,13 +374,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_output);

int lwtunnel_xmit(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
const struct lwtunnel_encap_ops *ops;
struct lwtunnel_state *lwtstate;
int ret = -EINVAL;
struct dst_entry *dst;
int ret;

if (dev_xmit_recursion()) {
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
__func__);
ret = -ENETDOWN;
goto drop;
}

if (!dst)
dst = skb_dst(skb);
if (!dst) {
ret = -EINVAL;
goto drop;
}

lwtstate = dst->lwtstate;

Expand All @@ -376,8 +401,11 @@ int lwtunnel_xmit(struct sk_buff *skb)
ret = -EOPNOTSUPP;
rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
if (likely(ops && ops->xmit))
if (likely(ops && ops->xmit)) {
dev_xmit_recursion_inc();
ret = ops->xmit(skb);
dev_xmit_recursion_dec();
}
rcu_read_unlock();

if (ret == -EOPNOTSUPP)
Expand All @@ -394,13 +422,23 @@ EXPORT_SYMBOL_GPL(lwtunnel_xmit);

int lwtunnel_input(struct sk_buff *skb)
{
struct dst_entry *dst = skb_dst(skb);
const struct lwtunnel_encap_ops *ops;
struct lwtunnel_state *lwtstate;
int ret = -EINVAL;
struct dst_entry *dst;
int ret;

if (!dst)
if (dev_xmit_recursion()) {
net_crit_ratelimited("%s(): recursion limit reached on datapath\n",
__func__);
ret = -ENETDOWN;
goto drop;
}

dst = skb_dst(skb);
if (!dst) {
ret = -EINVAL;
goto drop;
}
lwtstate = dst->lwtstate;

if (lwtstate->type == LWTUNNEL_ENCAP_NONE ||
Expand All @@ -410,8 +448,11 @@ int lwtunnel_input(struct sk_buff *skb)
ret = -EOPNOTSUPP;
rcu_read_lock();
ops = rcu_dereference(lwtun_encaps[lwtstate->type]);
if (likely(ops && ops->input))
if (likely(ops && ops->input)) {
dev_xmit_recursion_inc();
ret = ops->input(skb);
dev_xmit_recursion_dec();
}
rcu_read_unlock();

if (ret == -EOPNOTSUPP)
Expand Down

0 comments on commit 986ffb3

Please sign in to comment.